﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;

namespace ConsoleApplication1
{
    class Program
    {
        static string generalPath;
        static string resultadosPath;
        static string batchName;
        static List<string> paths = new List<string>();
        static List<string> nombresImagen = new List<string>();
        static Dictionary<int, List<string>> lineasArchivoPrueba = new Dictionary<int, List<string>>();
        static List<string> archivosPrueba = new List<string>();
        static List<Juego> juegosRealizados = new List<Juego>();
        static List<TimeSpan> tiemposEjecucion = new List<TimeSpan>();
        static List<List<Bitmap>> imagenesResultado = new List<List<Bitmap>>();
        static int cantBMP = 1;

        static void Main(string[] args)
        {

            bool leyendoModoBatch = true;
            bool modoBatch = false;

            ConsoleKeyInfo csi;
            while (leyendoModoBatch)
            {
                Console.WriteLine("\nSeleccione tipo de ingreso de archivos: B para Batch, M para Manual");//Luego preguntar si es absoluto o relativo

                csi = Console.ReadKey();
                switch (csi.Key)
                {
                    case ConsoleKey.B:
                        leyendoModoBatch = false;
                        modoBatch = true;
                        break;
                    case ConsoleKey.M:
                        leyendoModoBatch = false;
                        modoBatch = false;
                        break;
                    default:
                        Console.WriteLine("Ingrese Opcion Valida");
                        break;
                }
            }

            
            if(ingresarRutaArchivo(modoBatch))
            {
                if (modoBatch)
                {
                    if(abrirArchivoBatch())
                        Console.WriteLine("Archivos cargados exitosamente");
                    else
                        Console.WriteLine("No todos los archivos fueron cargados");
                }
                else
                {
                    cargarArgumentos(0);
                }
                generarSalida(modoBatch);
            }
            Console.WriteLine("Terminando Ejecucion");
            Console.ReadKey();
        }

        public static bool ingresarRutaArchivo(bool batch)
        {
            bool leyendoTipoPath = true;
            bool generacionExitosa = false;
            while (leyendoTipoPath)
            {
                Console.WriteLine("\nIngrese el tipo de ruta del archivo: A para Absoluta, R para Relativo");//Luego preguntar si es absoluto o relativo

                ConsoleKeyInfo csi = Console.ReadKey();
                switch (csi.Key)
                {
                    case ConsoleKey.A:
                        leyendoTipoPath = false;
                        generacionExitosa =abrirArchivo(false, batch);
                        break;
                    case ConsoleKey.R:
                        leyendoTipoPath = false;
                        generacionExitosa = abrirArchivo(true, batch);
                        break;
                    default:
                        Console.WriteLine("Valor invalido");
                        break;
                }
            }
            return generacionExitosa;
        }

        public static bool abrirArchivoBatch()
        {
            bool resultado = true;
            for (int i = 0; i < archivosPrueba.Count; i++)
            {
                string rutaArchivo = archivosPrueba.ElementAt(i);

                bool validarRuta = abrirArchivoRutaRelativa(rutaArchivo, false);
                if(validarRuta)
                    cargarArgumentos(i);
                else
                    Console.WriteLine("No se ha encontrado el archivo en "+rutaArchivo+" Siguiendo con siguiente elemento");
                resultado = validarRuta && resultado;
            }
            return resultado;
        }

        public static bool abrirArchivo(bool relativo, bool batch)
        {
            bool archivoEncontrado = false;
            if (relativo)
            {
                String rPath = "";

                Console.WriteLine("");
                Console.WriteLine("Ingrese ruta relativa");

                rPath = Console.ReadLine();
                while (rPath.Equals("") || !rPath.EndsWith(".txt"))
                {
                    Console.WriteLine("Ingrese ruta relativa valida con extension .txt");
                    rPath = Console.ReadLine();
                }
                
                archivoEncontrado = abrirArchivoRutaRelativa(rPath, batch);
            }
            else
            {
                string aPath = "";

                Console.WriteLine("");
                Console.WriteLine("Ingrese ruta absoluta");
                aPath = Console.ReadLine();
                while (aPath.Equals("") || !aPath.EndsWith(".txt"))
                {
                    Console.WriteLine("Ingrese ruta relativa valida con extension .txt");
                    aPath = Console.ReadLine();
                }

                archivoEncontrado = abrirArchivoRutaAbsoluta(aPath, batch);
                
            }

            if (archivoEncontrado)
                Console.WriteLine("Archivo cargado, se continua la ejecucion");
            else
                Console.WriteLine("Archivo no encontrado, se termina la ejecucion");

            return archivoEncontrado;
        }

        public static bool abrirArchivoRutaRelativa(string rPath, bool batch)
        {
            FileStream ifs;
            string path;
            try
            {
                ifs = new FileStream(rPath, FileMode.Open);
                StreamReader sr = new StreamReader(ifs);
                
                List<string> temporal = new List<string>();
                while (!sr.EndOfStream)
                {
                    string s = sr.ReadLine();

                    if (batch)
                    {
                        if (!s.Equals(""))
                        {
                            archivosPrueba.Add(@s);
                            
                        }
                    }
                    else
                    {
                        if (!s.Equals(""))
                        {
                            temporal.Add(s);
                        }
                    }                   
                }

                if (rPath.Contains("/"))
                {
                    string substr = rPath.Substring(0, rPath.LastIndexOf("/"));
                    if(batch)
                        batchName = rPath.Substring(rPath.LastIndexOf("/"), rPath.Length);
                    path = Directory.GetCurrentDirectory() + "/" + substr;
                }
                else
                {
                    if(batch)
                        batchName = rPath;
                    path = Directory.GetCurrentDirectory() + "/";
                }
                if (batch)
                {                    
                    batchName= batchName.Replace(".txt", "");
                    generalPath = path;
                }
                else 
                {
                    //contadorArchivos++;
                    lineasArchivoPrueba.Add(lineasArchivoPrueba.Count, temporal);
                    paths.Add(path);
                }

                ifs.Close();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public static bool abrirArchivoRutaAbsoluta(string aPath, bool batch)
        {
            FileStream ifs;
            string path;
            try
            {
                ifs = new FileStream(@aPath, FileMode.Open);
                StreamReader sr = new StreamReader(ifs);
                
                List<string> temporal = new List<string>();
                while (!sr.EndOfStream)
                {
                    string s = sr.ReadLine();
                    if (!s.Equals(""))
                    {
                        if (batch)
                        {
                            archivosPrueba.Add(s);
                        }
                        else
                        {
                            temporal.Add(s);
                        }
                    }
                }
                path = Path.GetDirectoryName(aPath);

                if (!batch)
                {
                    //contadorArchivos++;
                    lineasArchivoPrueba.Add(lineasArchivoPrueba.Count, temporal);
                    paths.Add(path);
                }
                else
                    generalPath = path;
                //path = Path.GetDirectoryName(aPath);

                ifs.Close();
                return true;
                //Console.WriteLine(path);
            }
            catch
            {
                return false;
            }
        }

        
        public static void generarSalida(bool batch)
        {
            if (batch)
            {
                string salida = null;
                for (int i = 0; i < archivosPrueba.Count; i++)
                {
                    salida += archivosPrueba.ElementAt(i) + " :" + tiemposEjecucion.ElementAt(i).Milliseconds + " ms\n";
                }
                Console.WriteLine("");
                Console.Write(salida);
                resultadosPath = @generalPath + "Resultado_" + batchName;
                Directory.CreateDirectory(resultadosPath);

                FileStream logStream = new FileStream(resultadosPath + "/log.txt", FileMode.OpenOrCreate);
                BinaryWriter bw = new BinaryWriter(logStream);

                bw.Write(salida);

                bw.Close();

                logStream.Close();

                for(int i = 0;i<imagenesResultado.Count;i++)
                {
                    List<Bitmap> listaBMP = imagenesResultado.ElementAt(i);
                    for (int j = 0; j < listaBMP.Count; j++)
                    {
                        Bitmap bmp = listaBMP.ElementAt(j);
                        string str = nombresImagen.ElementAt(i+j);
                        bmp.Save(resultadosPath + "\\" + str + "_Resultado.bmp", System.Drawing.Imaging.ImageFormat.Bmp);

                        bmp.Dispose();
                    } 
                }               
            }
            else
            {
                bool extensionIncorrecta = true;
                Console.WriteLine("Ingrese el nombre del archivo de Salida, incluyendo extension .bmp");
                string bmpResultadoName = Console.ReadLine();
                string extension = ".bmp";
                while (extensionIncorrecta)
                {                    
                    if (bmpResultadoName.EndsWith(extension))
                        extensionIncorrecta = false;
                    else
                    {
                        Console.WriteLine("Ingrese extension correcta .bmp");
                        bmpResultadoName = Console.ReadLine();
                    }
                }

                List<Bitmap> bmpResultado = imagenesResultado.ElementAt(0);

                for (int i = 0; i < bmpResultado.Count; i++)
                {
                    if (bmpResultado.Count == 1)
                    {
                        bmpResultado.ElementAt(i).Save(bmpResultadoName, System.Drawing.Imaging.ImageFormat.Bmp);
                        Console.WriteLine("Tiempo de ejecucion: "+tiemposEjecucion.ElementAt(i).Milliseconds+" ms");
                    }
                    else
                    {
                        bmpResultado.ElementAt(i).Save(bmpResultadoName + "_" + i);
                    }
                } 
            }
        }

        public static void cargarArgumentos(int posicion)
        {
            List<string> l = lineasArchivoPrueba[posicion];
            List<Bitmap> listaCapas = new List<Bitmap>();
            List<int[]> coordenadas = new List<int[]>();
            List<string> movimientos = new List<string>();
            string lineaEspecifica;
            if (l.Count > 0)
            {
                for (int i = 0; i < l.Count; i++)
                {
                    lineaEspecifica = l.ElementAt(i);

                    //Console.WriteLine(lineaEspecifica);
                    if (lineaEspecifica.EndsWith(".bmp") || lineaEspecifica.EndsWith(".BMP"))
                    {
                        string newPath = paths.ElementAt(posicion) + lineaEspecifica;
                        string fileName = lineaEspecifica.Replace(".bmp", "");
                        if (fileName.Contains("\\"))
                        {
                            string[] str = fileName.Split('\\');
                            
                            fileName = str[str.Length-1];
                        }
                        else
                            fileName = lineaEspecifica;
                        nombresImagen.Add(fileName);

                        try
                        {
                            Bitmap bm = new Bitmap(newPath);

                            //System.Diagnostics.Process.Start(fileName);

                            listaCapas.Add(bm);
                        }
                        catch
                        {
                            Console.WriteLine("Imagen no se encuentra en Ubicacion");
                        }
                    }
                    else
                    {
                        char[] separadores = { ';', '|' };

                        if (listaCapas.Count == 1)
                        {
                            string[] str = lineaEspecifica.Split(separadores);
                            int coordXA = Int32.Parse(str[0]);
                            int coordYA = Int32.Parse(str[1]);
                            int coordXB = Int32.Parse(str[2]);
                            int coordYB = Int32.Parse(str[3]);
                            int[] coords = new int[3];

                            if (coordXA - coordXB == 1)
                            {
                                coords = new int[] { coordXA, coordYA, 0 };
                                coordenadas.Add(coords);
                                movimientos.Add("L");//inv

                                coords = new int[] { coordXB, coordYB, 0 };
                                coordenadas.Add(coords);
                                movimientos.Add("R");//inv
                            }

                            if ((coordXA - coordXB == -1))
                            {
                                coords = new int[] { coordXA, coordYA, 0 };
                                coordenadas.Add(coords);
                                movimientos.Add("R");//ok

                                coords = new int[] { coordXB, coordYB, 0 };
                                coordenadas.Add(coords);
                                movimientos.Add("L");//ok

                            }

                            if (coordYA - coordYB == 1)
                            {
                                coords = new int[] { coordXA, coordYA, 0 };
                                coordenadas.Add(coords);
                                movimientos.Add("B");//inv

                                coords = new int[] { coordXB, coordYB, 0 };
                                coordenadas.Add(coords);
                                movimientos.Add("F");//inv
                            }

                            if ((coordYA - coordYB == -1))
                            {
                                coords = new int[] { coordXA, coordYA, 0 };
                                coordenadas.Add(coords);
                                movimientos.Add("F");//inv

                                coords = new int[] { coordXB, coordYB, 0 };
                                coordenadas.Add(coords);
                                movimientos.Add("B");//inv
                            }
                        }
                        else //3D
                        {
                            string[] str = lineaEspecifica.Split(separadores);
                            int coordXA = Int32.Parse(str[0]);
                            int coordYA = Int32.Parse(str[1]);
                            int coordZA = Int32.Parse(str[2]);
                            int coordXB = Int32.Parse(str[3]);
                            int coordYB = Int32.Parse(str[4]);
                            int coordZB = Int32.Parse(str[5]);
                            int[] coords = new int[3];

                            if (coordXA - coordXB == 1)
                            {
                                coords = new int[] { coordXA, coordYA, coordZA };
                                coordenadas.Add(coords);
                                movimientos.Add("L");//inv

                                coords = new int[] { coordXB, coordYB, coordZB };
                                coordenadas.Add(coords);
                                movimientos.Add("R");//inv
                            }

                            else if ((coordXA - coordXB == -1))
                            {
                                coords = new int[] { coordXA, coordYA, coordZA };
                                coordenadas.Add(coords);
                                movimientos.Add("R");//inv

                                coords = new int[] { coordXB, coordYB, coordZB };
                                coordenadas.Add(coords);
                                movimientos.Add("L");//inv

                            }

                            if (coordYA - coordYB == 1)
                            {
                                coords = new int[] { coordXA, coordYA, coordZA };
                                coordenadas.Add(coords);
                                movimientos.Add("B");//inv

                                coords = new int[] { coordXB, coordYB, coordZB };
                                coordenadas.Add(coords);
                                movimientos.Add("F");//inv
                            }

                            else if ((coordYA - coordYB == -1))
                            {
                                coords = new int[] { coordXA, coordYA, coordZA };
                                coordenadas.Add(coords);
                                movimientos.Add("F");//inv

                                coords = new int[] { coordXB, coordYB, coordZB };
                                coordenadas.Add(coords);
                                movimientos.Add("B");//inv

                            }

                            if (coordZA - coordZB == 1)
                            {
                                coords = new int[] { coordXA, coordYA, coordZA };
                                coordenadas.Add(coords);
                                movimientos.Add("U");//ok

                                coords = new int[] { coordXB, coordYB, coordZB };
                                coordenadas.Add(coords);
                                movimientos.Add("D");//ok
                            }

                            else if ((coordZA - coordZB == -1))
                            {
                                coords = new int[] { coordXA, coordYA, coordZA };
                                coordenadas.Add(coords);
                                movimientos.Add("D");//ok

                                coords = new int[] { coordXB, coordYB, coordZB };
                                coordenadas.Add(coords);
                                movimientos.Add("U");//ok

                            }
                        }
                    }
                }
            }

            Juego j = new Juego(listaCapas,coordenadas,movimientos);
            DateTime dt = System.DateTime.Now;
            if(j.ResolverPathFinds())
                Console.WriteLine("Resolviendo Caminos");
            j.PromediarColores();
            List<Bitmap> res = j.SetearImagenesOutput(cantBMP);
            imagenesResultado.Add(res);
            TimeSpan ts = System.DateTime.Now-dt;
            juegosRealizados.Add(j);//Ver si es conveniente guardarlo
            tiemposEjecucion.Add(ts);

            cantBMP =+ res.Count;
            /*
            if (imagenesResultado.Count == 0)
            {
                cantBMP+
            }
            else
            {
                cantBMP = 0;
                foreach (List<Bitmap> list in imagenesResultado)
                {
                    cantBMP += list.Count;
                }
            }*/
        }
    }
}